package cn.huiyunche.base.service.framework.security;

import cn.huiyunche.base.service.enums.AvailableEnum;
import cn.huiyunche.base.service.enums.UserTypeEnum;
import cn.huiyunche.base.service.framework.exception.AppError;
import cn.huiyunche.base.service.framework.utils.AppUtils;
import cn.huiyunche.base.service.framework.utils.JdbcTemplateUtils;
import cn.huiyunche.base.service.vo.UserVo;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * jwt认证过滤.
 * <p>
 * 当header中包含token时，通过本filter还原用户信息，供后续通过认证使用.
 *
 * @author zhaoshb
 * @since 0.0.1
 */
public class JwtAuthenicationFilter extends GenericFilterBean {

    public static final String HEADER_AUTHORIZATION = "Authorization";

    public static final String PREFIX_AUTHORIZATION = "Bearer ";

    private String secureKey = null;

    public JwtAuthenicationFilter(String secureKey) {
        this.secureKey = secureKey;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        String token = servletRequest.getHeader(JwtAuthenicationFilter.HEADER_AUTHORIZATION);
        if ((token == null) || !token.startsWith(JwtAuthenicationFilter.PREFIX_AUTHORIZATION)) {
            chain.doFilter(servletRequest, response);
            return;
        }
        String jwt = token.substring(7);
        try {
            UserVo user = JwtUtils.parseToken(jwt, this.getSecureKey());
            if (user != null && this.isUsedUser(user)) {
                Authentication authentication = this.createAuthentication(user);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                chain.doFilter(servletRequest, response);
                SecurityContextHolder.getContext().setAuthentication(null);
            } else {
                AppUtils.responseErrorJson(response, AppError.UserUnableInvalidError);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getCause().getMessage().startsWith("Form too large")) {
                AppUtils.responseErrorJson(response, AppError.FormTooLarge);
            }
            AppUtils.responseErrorJson(response, AppError.AuthenticationInvalidError);
        }
    }

    private Authentication createAuthentication(UserVo user) {
        return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
    }

    public String getSecureKey() {
        return this.secureKey;
    }

    /**
     * 判断用户是否可用
     *
     * @param username 用户名称
     * @param type     用户类别
     * @return 是否可用
     */
    private boolean isUsedUser(UserVo user) {
        String username = user.getUsername();
        int type = user.getType();
        if (StringUtils.isNotBlank(user.getUsername()) && null != UserTypeEnum.getByValue(type)) {
            Map<String, Object> map = JdbcTemplateUtils.getJdbcTemplate().queryForMap("SELECT count(1) as count FROM s_user WHERE phone = '" + username + "'  AND user_type = " + type + " AND enable = '" + AvailableEnum.T.getValue() + "'");
            JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(map));
            if (null != json && json.getIntValue("count") == 1) {
                return true;
            }
        }
        return false;
    }

}
